/*
 * Created on Apr 13, 2004
 */
package com.scalar.chiptrack.operations.process.actions;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;


import com.scalar.ScalarException;
import com.scalar.chiptrack.ChipTrackAction;
import com.scalar.chiptrack.utils.ConfigManager;
import com.scalar.chiptrack.commons.Labels;
import com.scalar.chiptrack.commons.SessionKeys;
import com.scalar.chiptrack.operations.process.PMFProcessInfo;
import com.scalar.chiptrack.operations.process.dao.PMFileDAO;
import com.scalar.chiptrack.operations.process.dao.ProductDao;


/**
 * @author Ravikanth
**/
public class PMFileAction extends ChipTrackAction
{
	private CellStyle cs 		= null;		// Cell Style for ordinary cells
	private CellStyle csBold 	= null;		// Cell Style for Process Names to appear in BOLD
	private int pmfCatlogRowIndex 	= 0;		// Row Index of the Parameter
	private int pmfCatalogColIndex	= 0;		// Col index of the product
	private String MFG_PART_NUMBER_KEY 		= null;
	private HashMap processStartIdxMap		= new HashMap();  // This Stores the value from where the Process Starts
	private HashMap processParameterIdxMap	= new HashMap();  // This Stores the row where the individual parameter starts

	public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
 	{
 		String productId 	= request.getParameter( "baseProductID" );
		pmfCatlogRowIndex 	= 0;
		pmfCatalogColIndex	= 0;
		HashMap errors		= new HashMap();

		try
		{
			 MFG_PART_NUMBER_KEY = MessageResources.getMessageResources( Labels.APPLICATION_RESOURCE_PROPERTIES ).getMessage("label.mfgPartNumber");
		}
		catch ( NullPointerException e )
		{
			 MFG_PART_NUMBER_KEY = Labels.DEFAULT_MFG_PART_NUMBER_LABEL;
		}

		try
		{
	 		String fileName  = createPmfFile( Integer.parseInt( productId ) );
            if( fileName == "" )
            {
                errors.put( "Product Master File could not be generated <br> as there are no Finished Goods for this product", null );
            }
            else
            {
                request.setAttribute( "productName", fileName );
            }
		}
		catch ( ScalarException se)
		{
			errors.put( "PMF could not be Created", null );
			//request.setAttribute( SessionKeys.ERROR_MESSAGES , errors );
			se.printStackTrace();
		}
        if ( errors.size() > 0  )
        {
            request.setAttribute( SessionKeys.ERROR_MESSAGES , errors );
        }
 		return mapping.findForward( "success" );
 	}

	/**
	 * @param productId
	 * @value  Creates a Excel File in the Default Location
	 */
	private String createPmfFile( int productId ) throws ScalarException
	{
		LinkedHashMap finishedGoodsMap 	 = new LinkedHashMap();
		LinkedHashMap processParameterLabelMap = new LinkedHashMap();
		Iterator itFinishedGoods		 = null;
		Iterator itProcessesMap 		 = null;
		String fgProcessStepID			 = null;
		LinkedHashMap processesMap		 = null;
		PMFProcessInfo processInfo		 = null;
		ArrayList parameterList			 = null;
		String parentProductName		 = null;
		String lastTestProcessName		 = null;
		boolean flag = true;

		try
		{
			finishedGoodsMap  = getFGProcessStepIds( productId );
			//parentProductName = PMFileDAO.getParentProductName( productId );
			parentProductName = ProductDao.getBaseProductName( productId+"" );
			if( finishedGoodsMap != null && finishedGoodsMap.isEmpty() == false  )
			{
				itFinishedGoods = finishedGoodsMap.keySet().iterator();
				while ( itFinishedGoods.hasNext() )
				{
					fgProcessStepID = (String)itFinishedGoods.next();
					processesMap 	= (LinkedHashMap)finishedGoodsMap.get( fgProcessStepID );
					if( flag  )
					{
						lastTestProcessName = getLastTest( processesMap );
					}

					itProcessesMap  = processesMap.keySet().iterator();

					while( itProcessesMap.hasNext() )
					{
						processInfo = ( PMFProcessInfo ) itProcessesMap.next();
						if( !processParameterLabelMap.containsKey( processInfo.getProcessName() ) )
						{
							if ( flag )
							{
								processParameterLabelMap.put( "Manufacturing Flow Identifiers", getProductInfo() );
								LinkedHashMap temp = (LinkedHashMap)processesMap.get( processInfo );
								Iterator it = temp.keySet().iterator();
								parameterList			 = new ArrayList();
								while( it.hasNext() )
								{
									parameterList.add( (String)it.next() );
								}
								processParameterLabelMap.put( processInfo.getProcessName(), parameterList );

								/*if( processInfo.getBaseProcessName().equalsIgnoreCase( "FAB" ) )
								{
									processParameterLabelMap.put( "WIP Gate#1", getWipGate( 1 ) );
									processParameterLabelMap.put( "WIP Gate#2", getWipGate( 2 ) );
									processParameterLabelMap.put( "WIP Gate#3", getWipGate( 3 ) );
								}*/

								/*if( processInfo.getBaseProcessName().equalsIgnoreCase( "SORT" ) )
								{
									processParameterLabelMap.put( "WIP Gate#4", getWipGate( 4 ) );
								}*/

								/*if( processInfo.getBaseProcessName().equalsIgnoreCase( "Assembly" ) )
								{
									processParameterLabelMap.put( "WIP Gate#5", getWipGate( 5 ) );
								}*/

								/*if( processInfo.getProcessName().equalsIgnoreCase( lastTestProcessName ) )
								{
									processParameterLabelMap.put( "WIP Gate#6", getWipGate( 6 ) );
								}*/
							}
							else
							{
								judgeThePosition( processParameterLabelMap, processesMap, processInfo );
							}
						}
						else
						{
							LinkedHashMap temp = (LinkedHashMap)processesMap.get( processInfo );
							Iterator it = temp.keySet().iterator();
							parameterList			 = new ArrayList();
							while( it.hasNext() )
							{
								parameterList.add( (String)it.next() );
							}

							checkForNewParameters( processInfo.getProcessName(), parameterList, processParameterLabelMap );
						}
					}
					flag = false;
				}
			}

			// This is placed here because it is the last Position
			/*if( finishedGoodsMap != null && finishedGoodsMap.isEmpty() == false  )
			{
				processParameterLabelMap.put( "WIP Gate#7", getWipGate( 7 ) );
			}*/
            // Added by Veeru on 6th September 2004
            if( finishedGoodsMap.isEmpty() == true )
            {
                parentProductName = "";
            }
            else
            {
                // Set the Product info to the FinishedGoodsMap
                setProductInfo( finishedGoodsMap );

                // To Generate the Excel File
                generateExcelFile( finishedGoodsMap, processParameterLabelMap, parentProductName );
            }
		}
		catch( Exception e )
		{
			e.printStackTrace();
			throw new ScalarException( "could not create PMF file" );
		}
		return parentProductName;
	}

    /**
	 * @param finishedGoodsMap
	 */
	private void setProductInfo( LinkedHashMap finishedGoodsMap ) throws ScalarException
	{
		Iterator it 				= finishedGoodsMap.keySet().iterator();
		Iterator itProcesses 		= null;
		LinkedHashMap processesMap 	= null;
		PMFProcessInfo process 		= null;
		PMFProcessInfo productInfo 	= null;
		LinkedHashMap productInfoMap= null;

		while( it.hasNext() )
		{
			processesMap = ( LinkedHashMap )finishedGoodsMap.get( it.next() );
			itProcesses  = processesMap.keySet().iterator();
			productInfoMap= new LinkedHashMap() ;
			while( itProcesses.hasNext() )
			{
				process = ( PMFProcessInfo )itProcesses.next();

				if( process.getBaseProcessName().equalsIgnoreCase( "FAB" ) )
				{
                    productInfoMap.put( "Base Die Part Number", process.getProductName() );
				}

				if( process.getBaseProcessName().equalsIgnoreCase( "Assembly" ) )
				{
                    productInfoMap.put( "Assembly OPN", process.getProductName() );
				}

				if( process.getBaseProcessName().equalsIgnoreCase( "Die Bank" ) )
				{
                    productInfoMap.put( "Die Part Number", process.getProductName() );
				}

				/*if( process.getBaseProcessName().equalsIgnoreCase( "Test" ) )
				{
					productInfoMap.put( "Test Part Number (Format: DPN-MMCC)", process.getProductName() );
				}*/

				if( process.getBaseProcessName().equalsIgnoreCase( "Finished Goods" ) )
				{

					HashMap finishedGoodsInfo = PMFileDAO.getFinishedGoodsInfo( process.getProcessStep_Id() );

					if( finishedGoodsInfo.containsKey( "Part_Number" ) )
					{
						productInfoMap.put( MFG_PART_NUMBER_KEY, (String)finishedGoodsInfo.get( "Part_Number" ) );
					}

					/*if( finishedGoodsInfo.containsKey( "P_Comments" ) )
					{
						productInfoMap.put( "Description", (String)finishedGoodsInfo.get( "P_Comments" ) );
					}*/

					if( finishedGoodsInfo.containsKey( "P_Marketing_Part_Number" ) )
					{
						productInfoMap.put( "Marketing Part Number", (String)finishedGoodsInfo.get( "P_Marketing_Part_Number" ) );
					}

					if( finishedGoodsInfo.containsKey( "IS_Approved" ) )
					{
						String approved = ( ((String)finishedGoodsInfo.get( "IS_Approved" )).equalsIgnoreCase("1") ? "Not Active" : "Active" );
						productInfoMap.put( "Status (Active or Obsolete)", approved );
					}

					if( finishedGoodsInfo.containsKey( "Product Family" ) )
					{
						productInfoMap.put( "Product Family", (String)finishedGoodsInfo.get( "Product Family" ) );
					}
				}
			}
			productInfo = new PMFProcessInfo();
			productInfo.setProcessName( "Manufacturing Flow Identifiers" );
			processesMap.put( productInfo, productInfoMap );
		}
	}

	private void checkForNewParameters( String processName, ArrayList parameterList, LinkedHashMap processParameterLabelMap )
	{
		ArrayList exitingParameterList = (ArrayList)processParameterLabelMap.get( processName );

		for( int i = 0; i < parameterList.size(); i++ )
		{
			if( !( exitingParameterList.contains( parameterList.get( i ) ) ) )
			{
				exitingParameterList.add( parameterList.get( i ) );
			}
		}
	}

	private void generateExcelFile( LinkedHashMap finishedGoodsMap, LinkedHashMap processParameterLabelMap, String parentProductName )
	{
		Workbook wb = null;
        if ( "xlsx".equalsIgnoreCase(ConfigManager.getXLSWorkBookFormat() ) )
        {
            wb    = new XSSFWorkbook();
        }
        else
        {
            wb    = new HSSFWorkbook();
        }
        CreationHelper ch = wb.getCreationHelper();
        DataFormat df = ch.createDataFormat();

		Sheet sheet = wb.createSheet( "PMF Catalog Active" );
		String[] labels	= null;
		String filePath = null;

		Font f 		= wb.createFont();
		Font fBold 	= wb.createFont();
		cs 				= wb.createCellStyle();
		csBold			= wb.createCellStyle();

		f.setFontName  ( "verdana" );
		f.setFontHeight( (short)150 );
		cs.setFont( f );
		//cs.setWrapText( true );

		fBold.setFontName( "verdana" );
		fBold.setFontHeight( (short)150 );
		fBold.setBoldweight( Font.BOLDWEIGHT_BOLD );
		csBold.setFont( fBold );
		//csBold.setWrapText( true );

		// This Block creates the Lables i.e the First column in the PMF file.
		// Set the first column width
		sheet.setColumnWidth( (short) pmfCatalogColIndex++, (short)8000 );
		createProductLabels( sheet, processParameterLabelMap );

		// Add the second column in the PMF file
		// Numbering And Flow Schema. Presently creating an Empty Column
		// Set the second column width
		sheet.setColumnWidth( (short) pmfCatalogColIndex++, (short)2000 );

		createProductData( sheet, finishedGoodsMap );

		FileOutputStream fileOut;
		try
		{
			filePath = getServlet().getServletContext().getRealPath( ConfigManager.getPmfFilePath() );
			boolean exists = ( new File( filePath ) ).exists();
			if ( !exists )
			{
				File file = new File( filePath );
                file.mkdirs(); // Added by Krishna 14 July 2004
			}

			fileOut = new FileOutputStream( filePath + "/" +parentProductName );
			wb.write( fileOut );
			fileOut.close();
		}
		catch ( Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * @param sheet
	 * @param finishedGoodsMap
	 */
	private void createProductData( Sheet sheet, LinkedHashMap finishedGoodsMap )
	{
		Iterator itFinishedGoods	= null;
		Iterator itProcessesMap 	= null;
		Iterator itParameterMap		= null;
		LinkedHashMap processesMap	= null;
		LinkedHashMap parameterMap	= null;
		PMFProcessInfo process		= null;

		if( finishedGoodsMap != null && finishedGoodsMap.isEmpty() == false )
		{
			itFinishedGoods = finishedGoodsMap.keySet().iterator();

			while ( itFinishedGoods.hasNext() )
			{
				pmfCatlogRowIndex = 0;

				sheet.setColumnWidth( (short) pmfCatalogColIndex, (short) 7000 );
				processesMap = ( LinkedHashMap ) finishedGoodsMap.get( (String) itFinishedGoods.next() );

				if( processesMap != null && processesMap.isEmpty() == false )
				{
					itProcessesMap = processesMap.keySet().iterator();

					while( itProcessesMap.hasNext() )
					{
						process			= ( PMFProcessInfo )itProcessesMap.next();
						parameterMap 	= ( LinkedHashMap )processesMap.get( process );

						if( parameterMap != null && parameterMap.isEmpty() == false )
						{
							//pmfCatlogRowIndex = Integer.parseInt((String)processStartIdxMap.get( process.getProcessName() ));
							//pmfCatlogRowIndex++;  // This is incremented because the first cell contains the name of the process and parameters start only after the first cell.
							itParameterMap 	= parameterMap.keySet().iterator();
							while( itParameterMap.hasNext() )
							{
								Object parameter  = itParameterMap.next();
								pmfCatlogRowIndex = Integer.parseInt((String)((HashMap)processParameterIdxMap.get( process.getProcessName() )).get( parameter ) );
								setCellValue( sheet, pmfCatlogRowIndex, (String)parameterMap.get( parameter ) );
							}
						}
						pmfCatlogRowIndex++;
						pmfCatlogRowIndex++;
					}
				}
				pmfCatalogColIndex++;
			}
		}
	}

	/**
	 * @value sets the cell value at the required Cell in the Excel File
	 */
	private void setCellValue( Sheet sheet, int rowIdx, String value  )
	{
		Row row 	= sheet.getRow( rowIdx );
        Cell cell 	= row.createCell( (short) pmfCatalogColIndex );
		cell.setCellValue( value );
		cell.setCellStyle( cs );
	}

	/**
	 * @param sheet
	 * @param processParameterLabelMap
	 */
	private void createProductLabels( Sheet sheet, LinkedHashMap processParameterLabelMap )
	{
		ArrayList parameterList 	= null;
		HashMap parameterLabelIdxMap= null;
		Iterator it 	= processParameterLabelMap.keySet().iterator();
		String process 	= null;
		Row row 	= null;
		Cell cell 	= null;

		while( it.hasNext() )
		{
			process 		= ( String )it.next();
			parameterList 	= ( ArrayList )processParameterLabelMap.get( process );

			processStartIdxMap.put( process, pmfCatlogRowIndex+"" );

			row 	= sheet.createRow( (short) pmfCatlogRowIndex++ );
			cell 	= row.createCell( (short) 0 );
			row.setHeight((short)250);
			cell.setCellValue( process );
			cell.setCellStyle( csBold );
			parameterLabelIdxMap = new HashMap();

			for ( int i = 0; i < parameterList.size(); i++ )
			{
				parameterLabelIdxMap.put( parameterList.get( i ), pmfCatlogRowIndex+"" );
				row 	= sheet.createRow( (short) pmfCatlogRowIndex++ );
				cell 	= row.createCell( (short) 0 );
				row.setHeight((short)250);
				cell.setCellValue( (String) parameterList.get( i ) );
				cell.setCellStyle( cs );
			}

			processParameterIdxMap.put( process, parameterLabelIdxMap );
			createEmptyLine( sheet );
		}
	}

	private void judgeThePosition( LinkedHashMap processParameterLabelMap, LinkedHashMap processesMap, PMFProcessInfo processInfo )
	{
		LinkedHashMap temp 		= (LinkedHashMap)processesMap.get( processInfo );
		ArrayList parameterList	= new ArrayList();
		Iterator itProcesses	= processParameterLabelMap.keySet().iterator();
		Iterator it 			= temp.keySet().iterator();
		Object lastObjectKey	= null;
		Object lastObjectValue	= null;
		while( it.hasNext() )
		{
			parameterList.add( (String)it.next() );
		}

		while( itProcesses.hasNext() )
		{
			lastObjectKey	= itProcesses.next();
		}

		lastObjectValue	= processParameterLabelMap.get( lastObjectKey );

		processParameterLabelMap.remove( lastObjectKey );

		processParameterLabelMap.put( processInfo.getProcessName(), parameterList );
		processParameterLabelMap.put( lastObjectKey, lastObjectValue );
		//processParameterLabelMap.add( processParameterLabelList.size()-1 , processInfo.getProcessName() );
	}

	/**
	 * @param productId
	 */
	private LinkedHashMap getFGProcessStepIds( int productId ) throws ScalarException
	{
		LinkedHashMap finishedGoodsMap 	= new LinkedHashMap();
        LinkedHashMap newFinishedGoodsMap   = new LinkedHashMap();
		LinkedHashMap processesMap 	= null;
		Iterator itFinishedGoods	= null;
		String fgProcessStepId		= null;

		// Here we are fetching all the Finshed Goods for this BaseProduct
		finishedGoodsMap = PMFileDAO.getFinishedGoodsMap( productId );

		if( finishedGoodsMap != null && finishedGoodsMap.isEmpty() == false )
		{
			itFinishedGoods = finishedGoodsMap.keySet().iterator();

			while( itFinishedGoods.hasNext() )
			{
				fgProcessStepId = (String)itFinishedGoods.next();
				//System.out.println( "Finished Goods Process StepIDs " + fgProcessStepId );
				ArrayList processesMapList 	= getProcessesMap( fgProcessStepId );
                int processesMapListSize    = processesMapList.size();
                String spaces = "";
                for ( int i=0; i < processesMapListSize; i++ )
                {
                    spaces  = spaces + " ";
                    processesMap    = ( LinkedHashMap )processesMapList.get( i );
                    //spaces are added to the fgprocessStepId to distinguish the keys..
				    //finishedGoodsMap.put( fgProcessStepId + spaces, processesMap );
                    newFinishedGoodsMap.put ( fgProcessStepId + spaces, processesMap );
                }
			}
		}
		return newFinishedGoodsMap;
	}

	/**
	 * @param fgProcessStepId
	 * @return returns the map of all processes for the Finished goods
	 */
	private ArrayList getProcessesMap( String fgProcessStepId ) throws ScalarException
	{
        ArrayList   processesMapList    = null;
		LinkedHashMap processesMap 	= new LinkedHashMap();
		LinkedHashMap parameterMap 	= new LinkedHashMap();
		Iterator itProcesses 		= null;
		PMFProcessInfo processInfo	= null;

		// fetch all the Processes for this Finished Goods
		processesMapList = PMFileDAO.getProcessesMap( fgProcessStepId );
        int processesMapListSize    = ( processesMapList == null ) ? 0 : processesMapList.size();
        for ( int i = 0; i < processesMapListSize; i++ )
        {
            processesMap    = ( LinkedHashMap ) processesMapList.get ( i );
            if( processesMap != null && processesMap.isEmpty() == false )
            {
                itProcesses = processesMap.keySet().iterator();

                while( itProcesses.hasNext() )
                {
                    processInfo		= (PMFProcessInfo) itProcesses.next();
                    // Fetch the Process Parameters for each Process
                    parameterMap  	= getProcessParameters( processInfo.getProcessStep_Id() );
                    processesMap.put( processInfo, parameterMap );
                }
            }
        }

		return processesMapList;
	}

	/**
	 * @param processStepId
	 * @return map of all the parameters for the process
	 */
	private LinkedHashMap getProcessParameters( int processStepId ) throws ScalarException
	{
		LinkedHashMap parameterMap 	= new LinkedHashMap();
		parameterMap 		 		= PMFileDAO.getParameterMap( processStepId );
		return parameterMap;
	}

	private void createEmptyLine( Sheet sheet )
	{
		Row row 	= sheet.createRow( (short) pmfCatlogRowIndex++ );
	}


	private ArrayList getWipGate( int gate )
	{
		ArrayList labels = new ArrayList();

		labels.add( "WIP Gate #"+ gate +" Name" );
		labels.add( "WIP Gate #"+ gate +" Min Inventory Level" );
		labels.add( "WIP Gate #"+ gate +" Max Inventory Level" );
		labels.add( "WIP Gate #"+ gate +" Safety Stock Level" );
		labels.add( "WIP Gate #"+ gate +" ConWIP Lot size" );
		labels.add( "WIP Gate #"+ gate +" Cycle Time" );
		labels.add( "WIP Gate #"+ gate +" Line Yield" );

		return labels;
	}

	private ArrayList getProductInfo()
	{
		ArrayList labels = new ArrayList();

		labels.add( MFG_PART_NUMBER_KEY );
		//labels.add( "Description" );
		//labels.add( "Die Revision" );
		//labels.add( "Manufacturing Flow" );
		//labels.add( "Customer Code" );
		labels.add( "Date when PMF last modified" );
		//labels.add( "Engineering Project Name" );
		labels.add( "Product Family" );
		labels.add( "Marketing Part Number" );
		//labels.add( "Catalog or Custom" );
		labels.add( "Status (Active or Obsolete)" );
		//labels.add( "Manufacturing Numbering System" );
		labels.add( "Base Die Part Number" );
		labels.add( "Die Part Number" );
		labels.add( "Assembly OPN" );
		//labels.add( "Test Part Number (Format: DPN-MMCC)" );

		return labels;
	}

	/**
	 * @param processesMap
	 * @return String
	 * @value returns the Last Test Name to provide the WipGate6 information
	 */
	private String getLastTest( LinkedHashMap processesMap )
	{
		String lastTestName = null;
		Iterator it = processesMap.keySet().iterator();
		PMFProcessInfo process = null;
		while( it.hasNext() )
		{
			process = ( PMFProcessInfo ) it.next();
			if( process.getBaseProcessName().equalsIgnoreCase( "Test" ) )
			{
				lastTestName = process.getProcessName();
			}
		}

		return lastTestName;
	}

}
